/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.model.disc.analysismodel;

import java.text.DecimalFormat;
import java.util.ListIterator;

import br.ufmg.dees.insane.materialMedia.material.Material;
import br.ufmg.dees.insane.model.disc.element.FrameElement;
import br.ufmg.dees.insane.model.disc.element.ParametricElement;
import br.ufmg.dees.insane.model.disc.fem.FemModel;
import br.ufmg.dees.insane.model.disc.node.Node;
import br.ufmg.dees.insane.util.IMatrix;
import br.ufmg.dees.insane.util.IVector;


/**
*A class representing an solid analysis model of a ParametricElement.
*
*@author Lucas, Marcelo & Pitangueira, Roque.
*@version 1.0
*@since september 2004
*@see model.discrete.element.ParametricElement
*/

public class SolidAnalysisM extends AnalysisModel implements java.io.Serializable 
{

//********************************************************************************

	private static final long serialVersionUID = 1L;

	/** Constructs a SolidAnalysisM analysis model, sets its ndf and dominion to 3 and define validEquations.*/	
	public SolidAnalysisM()
	{
		this.setDominion(3);
		this.setNdf(3);
		this.setValidEquation(0,true);
		this.setValidEquation(1,true);
		this.setValidEquation(2,true);
		this.setValidEquation(3,false);
		this.setValidEquation(4,false);
		this.setValidEquation(5,false);
		this.setType("SolidAnalysisM");
	}
	
//********************************************************************************
	
	/** Mounts the matrix of the material properties for the analysis model type.
	*@param a The matrix of material properties.
	*@return matrix D related to analysis model type 
	*/
	public IMatrix mountDMatrix(double[][] a)
	{
		IMatrix d = new IMatrix(6,6);
		
		double elast = a[0][0];
		double ni = a[2][0];
		double k = ((elast)/((1+ni)*(1-(2*ni))));
		
		d.setElement(0,0, ((1*k)*(1-ni)));
		d.setElement(0,1, (ni*k));
		d.setElement(0,2, (ni*k));
		d.setElement(0,3, 0);
		d.setElement(0,4, 0);
		d.setElement(0,5, 0);
		d.setElement(1,0, (ni*k));
		d.setElement(1,1, ((1*k)*(1-ni)));
		d.setElement(1,2, (ni*k));
		d.setElement(1,3, 0);
		d.setElement(1,4, 0);
		d.setElement(1,5, 0);
		d.setElement(2,0, (ni*k));
		d.setElement(2,1, (ni*k));
		d.setElement(2,2, ((1*k)*(1-ni)));
		d.setElement(2,3, 0);
		d.setElement(2,4, 0);
		d.setElement(2,5, 0);
		d.setElement(3,0, 0);
		d.setElement(3,1, 0);
		d.setElement(3,2, 0);
		d.setElement(3,3, (0.5*(1-(2*ni))));
		d.setElement(3,4, 0);
		d.setElement(3,5, 0);
		d.setElement(4,0, 0);
		d.setElement(4,1, 0);
		d.setElement(4,2, 0);
		d.setElement(4,3, 0);
		d.setElement(4,4, (0.5*(1-(2*ni))));
		d.setElement(4,5, 0);
		d.setElement(5,0, 0);
		d.setElement(5,1, 0);
		d.setElement(5,2, 0);
		d.setElement(5,3, 0);
		d.setElement(5,4, 0);
		d.setElement(5,5, (0.5*(1-(2*ni))));
		
			return(d);
	}
	
//********************************************************************************
	
	/** Return the number of active stresses according to this Analysis model type.*/
	public int getNumberOfActiveStress()
	{
		return 6;
	}
	
//********************************************************************************
	
	/** Return the number of active strains according to this Analysis model type.*/
	public int getNumberOfActiveStrains()
	{
		return 6;
	}
	
//********************************************************************************
	
	/** Return the non zero stresses that perform in one point. 
	*@param a The IVector containing stresses of the point.
	*@param b The Material that will be used to obtain material properties.
	*@return stressVector The IVector according this Plane Analysis Model.
	*/
	public IVector getStressVector(IVector a, Material b)
	{
		return a;
	}
	
//********************************************************************************
	
	/** Return the non zero strains that perform in one point. 
	*@param a The IVector containing strains of the point.
	*@param b The Material that will be used to obtain material properties.
	*@return strainVector The IVector according this Plane Analysis Model.
	*/
	public IVector getStrainVector(IVector a, Material b)
	{
		return a;
	}
	
//********************************************************************************
	
	/** Return the String representing the non zero stresses of this Analysis Model.
	*@return The string containing the label of non zero stresses of this Analysis Model.
	*/
	public String getStressLabels()
	{
		return ("sigmaXX sigmaYY sigmaZZ tauXY tauYZ tauZX");
	}
	
//********************************************************************************
	
	/** Return the string representing the non zero strains of this Plane Analysis Model.
	*@return The string containing the label of non zero strains of this Plane Analysis Model.
	*/
	public String getStrainLabels()
	{
		return ("epsilonXX epsilonYY epsilonZZ gammaXY gammaYZ gammaZX");
	}
	
//********************************************************************************

	/** Returns the B matrix related to this SolidAnalysisM 
	*@param dl The matrix containing local derivates of shape functions.
	*@param n The vector containing shape functions in natural coordinates.
	*@param cN The matrix containing nodal coordinates in cartesian system.
	*@return The matrix B 
	*/
	public IMatrix mountBMatrix(IMatrix dl, IVector n, IMatrix cN) 
	{
		int nNos = dl.getNumCol();
		IMatrix invertJacobian;
		IMatrix dG = new IMatrix(3,dl.getNumCol());
		IMatrix b = new IMatrix(6,(3*nNos));
		dG.setZero();
		b.setZero();
		
		invertJacobian = this.invertJacobian(this.getJacobian(dl, cN));
		dG.mul(invertJacobian, dl);
		
		for(int i = 0; i < nNos; i++) 
		{
			b.setElement(0,(3*i),dG.getElement(0,i));
			b.setElement(1,((3*i)+1),dG.getElement(1,i));
			b.setElement(2,((3*i)+2),dG.getElement(2,i));
			b.setElement(3,(3*i),dG.getElement(1,i));
			b.setElement(3,((3*i)+1),dG.getElement(0,i));
			b.setElement(4,((3*i)+1),dG.getElement(2,i));
			b.setElement(4,((3*i)+2),dG.getElement(1,i));
			b.setElement(5,(3*i),dG.getElement(2,i));
			b.setElement(5,((3*i)+2),dG.getElement(0,i));
		}
			return(b);
	}
	
//********************************************************************************	
	
	/** Return the inverse of jacobian matrix.
	*@param a The jacobian matrix.
	*@return the inverse of jacobian matrix.
	*/
	protected IMatrix invertJacobian(IMatrix a)
	{
		IMatrix b = new IMatrix(3,3);
		b.setZero();
		
		b.setElement(0,0, (((a.getElement(1,1))*(a.getElement(2,2)))-((a.getElement(1,2))*(a.getElement(2,1)))));
		b.setElement(0,1, (-1)*(((a.getElement(1,0))*(a.getElement(2,2)))-((a.getElement(1,2))*(a.getElement(2,0)))));
		b.setElement(0,2, (((a.getElement(1,0))*(a.getElement(2,1)))-((a.getElement(1,1))*(a.getElement(2,0)))));
		b.setElement(1,0, (-1)*(((a.getElement(0,1))*(a.getElement(2,2)))-((a.getElement(0,2))*(a.getElement(2,1)))));
		b.setElement(1,1, (((a.getElement(0,0))*(a.getElement(2,2)))-((a.getElement(0,2))*(a.getElement(2,0)))));
		b.setElement(1,2, (-1)*(((a.getElement(0,0))*(a.getElement(2,1)))-((a.getElement(0,1))*(a.getElement(2,0)))));
		b.setElement(2,0, (((a.getElement(0,1))*(a.getElement(1,2)))-((a.getElement(0,2))*(a.getElement(1,1)))));
		b.setElement(2,1, (-1)*(((a.getElement(0,0))*(a.getElement(1,2)))-((a.getElement(0,2))*(a.getElement(1,0)))));
		b.setElement(2,2, (((a.getElement(0,0))*(a.getElement(1,1)))-((a.getElement(0,1))*(a.getElement(1,0)))));
		
		b.transpose();
		b.setScale((1/(a.determinantLU())));
		
		return b;
	}

//********************************************************************************
	
	/** Prints in the screen a table with the valid nodal displacements for this AnalysisModel type.
	*@param mod The FemModel which contains the data to be printed.
	*/
	public void printDisplacements(FemModel mod)
	{
		DecimalFormat fmt = new DecimalFormat();
		fmt.applyPattern("0.000E00");
		Node node;
		ListIterator nodes = mod.getNodesList().listIterator();
		System.out.println("NODE DISPLACEMENTS:");
		System.out.println("Node" +"\t\t"+ "Dx" +"\t\t"+ "Dy" +"\t\t\t"+ "Dz");

		while (nodes.hasNext()) 
		{
			node = (Node) nodes.next();
			System.out.println("Node " + node.getLabel() +"\t"+ fmt.format(node.getDisplacement(0)) +"\t\t"+ fmt.format(node.getDisplacement(1)) +"\t\t"+ fmt.format(node.getDisplacement(2)));
		}
		System.out.println("\t");
	}
	
//********************************************************************************
	/** Prints in the screen a table with the valid support reactions for this AnalysisModel type.
	*@param mod The FemModel which contains the data to be printed.
	*/
	public void printReactions(FemModel mod)
	{
		Node node;
		ListIterator nodes = mod.getNodesList().listIterator();
		System.out.println("SUPPORT REACTIONS:");
		System.out.println("Node" +"\t"+ "Rx" +"\t\t"+ "Ry" +"\t\t"+ "Rz");
		
		while (nodes.hasNext())
		{
			node = (Node) nodes.next();
			boolean hasRestraint = false;
			for (int i=0; i<(mod.getGlobalAnalysisModel().getNdf()); i++)
				if (node.getRestraint(i))
					hasRestraint = true;
			if (hasRestraint)
				System.out.println("Node " + node.getLabel() +"\t"+ (node.getReaction(0)) +"\t"+ (node.getReaction(1)+"\t"+ (node.getReaction(2))));
		}
		System.out.println("\t");
	}
	
//********************************************************************************

	/** Prints in the screen a table with the valid actions at elements' extremities for the AnalysisModel type.
	*@param femModel The FemModel which contains the data to be printed.
	*/
	public void printActionsAtExtremities(FemModel femModel)
	{
	}
	
//********************************************************************************
	
	/** Return the integration factor according to analysis model type.
	*This method will be important for AxiSymetricAnalysisM.
	*@param n The vector containing the shape functions.
	*@param cN The matrix containing the nodal coordinates in cartesian system.
	*@return The integration factor wich for this analysis model is equals to one.
	*/
	public double getStiffnessFactor(IVector n, IMatrix cN)
	{
		return 1;
	}
	
//********************************************************************************
	
	/** Return the jacobian matrix.
	*@param dl The matrix of local derivates.
	*@param cN The matrix of nodal coordinates.
	*@return dl * cN The jacobian matrix.
	*/
	public IMatrix getJacobian(IMatrix dl, IMatrix cN)
	{
		IMatrix jacobian = new IMatrix(this.getDominion(),this.getDominion());
		jacobian.setZero();
		jacobian.mul(dl, cN);
		
		return(jacobian);
	}
	
//********************************************************************************
	
	/** Returns the type of the Shape adequate to the type of AnalysisModel.
	*@return The type of the Shape adequate to the type of AnalysisModel.
	*/
	public String getDefaultShapeType()
	{
		return null;
	}
	
	/** Returns the nodal rotation matrix of the specified ParametricElement, accordingly to this AnalysisModel type.
	*@param elm The ParametricElement whose nodal rotation matrix is desired.
	*@return The nodal rotation matrix of the specified ParametricElement, accordingly to this AnalysisModel type.
	*/
	public IMatrix nodalRotationMatrix(ParametricElement elm)
	{
		return null;
	}
	
	/** Returns the local stiffness matrix of the specified ParametricElement, accordingly to its AnalysisModel type.<br>
	*This matrix does not consider the possible liberations at the extremities of the ParametricElement.
	*@param elm The ParametricElement whose local stiffness matrix is desired.
	*@return The local stiffness matrix of the specified ParametricElement, accordingly to its AnalysisModel type.
	*/
	public IMatrix localStiffnessMatrix(ParametricElement elm)
	{
		return null;
	}
	
	/** Returns the corrected local stiffness matrix of the specified ParametricElement, accordingly to its AnalysisModel type.
	*This matrix is corrected to consider the liberations at the extremities of the ParametricElement.
	*@param elm The ParametricElement whose corrected local stiffness matrix is desired.
	*@return The corrected local stiffness matrix of the specified ParametricElement, accordingly to its AnalysisModel type.
	*/
	public IMatrix localCorrectedStiffnessMatrix(ParametricElement elm)
	{
		return null;
	}
	
	/** Returns the transformation matrix of the specified ParametricElement, accordingly to its AnalysisModel type.
	*@param elm The ParametricElement whose transformation matrix is desired.
	*@return The transformation matrix of the specified ParametricElement, accordingly to its AnalysisModel type.
	*/
	public IMatrix transformationMatrix(ParametricElement elm)
	{
		return null;
	}
	
	/** Returns the local equivalent nodal force vector of the specified ParametricElement, accordingly to the AnalysisModel type.
	*This vector does not consider the possible liberations at the extremities of the ParametricElement.
	*@param elm The ParametricElement whose local equivalent nodal force vector is desired.
	*@return The local equivalent nodal force vector of the specified ParametricElement, accordingly to the AnalysisModel type.
	*/
	public IVector localEquivalentForceVector(ParametricElement elm)
	{
		return null;
	}
	
	/** Returns the corrected local equivalent nodal force vector of the specified ParametricElement, accordingly to the AnalysisModel type.
	*This matrix is corrected to consider the liberations at the extremities of the ParametricElement.
	*@param elm The ParametricElement whose corrected local equivalent nodal force vector is desired.
	*@return The corrected local equivalent nodal force vector of the specified ParametricElement, accordingly to the AnalysisModel type.
	*/
	public IVector localCorrectedEquivalentForceVector(ParametricElement elm)
	{
		return null;
	}
	
	/** Mounts the shape function matrix accordingly to the AnalysisModel type with the values of two IVectors.<br>
	*The first IVector must contain the shape functions values which will be put in the upper part of the matrix.<br>
	*The second IVector must contain the shape functions values which will be put in the lower part of the matrix (related to the derivated shape functions).
	*@param n1 A IVector containing the shape functions values which will be put in the upper part of the matrix.
	*@param n2 A IVector containing the shape functions values which will be put in the upper part of the matrix.
	*@return The shape function matrix accordingly to the AnalysisModel type.
	*/
	public IMatrix mountMatrixN(IVector n1, IVector n2)
	{
		return null;
	}
	
	/**Return the matrix with the shape functions ordered according the AnalysisModel.
	*@param n The IVector containing the values of shape functions evalueted in one point.
	*@return matrixN The IMatrix with the shape functions ordered according the AnalysisModel.
	*/
	public IMatrix mountMatrixN(IVector n1)
	{
		IMatrix matrixN = new IMatrix((this.getNdf()),((this.getNdf())*(n1.getSize())));
		matrixN.setZero();
		
		for(int i = 0; i < (n1.getSize()); i++)
		{
			for(int j = 0; j < (this.getNdf()); j++)
			{
				matrixN.setElement( j, ((this.getNdf()*i)+j), (n1.getElement(i)));
			}
		}
			return matrixN;
	}
	
	public IMatrix transformationMatrix(FrameElement elm) {
		return null;
	} 
	
}
